package com.customization.qs.download.util;

import DBstep.iMsgServer2000;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import weaver.conn.ConnStatement;
import weaver.conn.RecordSet;
import weaver.file.AESCoder;
import weaver.general.BaseBean;
import weaver.general.Util;
import weaver.integration.logging.Logger;
import weaver.integration.logging.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.List;
import java.util.zip.ZipInputStream;

public class DownLoadUtils {

    private static BaseBean baseBean = new BaseBean();

    private static Logger log = LoggerFactory.getLogger(DownLoadUtils.class);

    public static void getDocInfo(String docIds, String fileTempFolder, List<String> fileRealPathList, List<String> fileRealPathTempList) {
        log.info("进入获取文档信息");
        RecordSet rsImageFileId = new RecordSet();
        // 查询文档
        String sqlImageFileId = "select b.imagefileid from docdetail a, docimagefile b where a.id=b.docid and a.id in (" + docIds + ") " +
                " and b.versionId = (select max(c.versionId) from docimagefile c where c.id =b.id) order by a.id asc";
        rsImageFileId.executeQuery(sqlImageFileId);
        int counts = rsImageFileId.getCounts();
        if (counts <= 0) {
            log.info("查询文件数量为空！");
        } else {
            String docImageFileIds = "";
            int num = 0;
            while (rsImageFileId.next()) {
                num++;
                if (num == counts) {
                    docImageFileIds += Util.null2String(rsImageFileId.getString("imagefileid"));
                } else {
                    docImageFileIds += Util.null2String(rsImageFileId.getString("imagefileid")) + ",";
                }
            }

            File fileTemp = null;

            String sqlFileRealPath = "select t1.imagefilename,t1.filerealpath,t1.imagefileid,t2.imagefilename as realname " +
                    " from imagefile t1 " +
                    " left join docimagefile  t2 " +
                    " on t1.imagefileid = t2.imagefileid " +
                    " where t1.imagefileid  in (" + docImageFileIds + ") and t2.docid in (" + docIds + ")";
            log.info("sqlFileRealPath：" + sqlFileRealPath);
            rsImageFileId.executeQuery(sqlFileRealPath);
            while (rsImageFileId.next()) {
                try {
                    String imagefileid = Util.null2String(rsImageFileId.getString("imagefileid"));
                    String filename = Util.null2String(rsImageFileId.getString("realname"));
                    log.info("文档附件realname:" + filename + "，文档附件imagefileid:" + imagefileid);
                    if ("".equals(filename)) {
                        filename = Util.null2String(rsImageFileId.getString("imagefilename"));
                    }
                    String filerealpath = Util.null2String(rsImageFileId.getString("filerealpath"));
                    log.info("文档附件filerealpath:" + filerealpath + "，文档附件imagefilename:" + filename);
                    /** 文档相关开始*/
                    // 流程下载附件，获取最新版本附件下载
                    RecordSet rs = new RecordSet();
                    String sql = "select doceditionid,id from docdetaill where id (select max(docid) from docimagefile where imagefileid = " + imagefileid + ")";
                    rs.executeQuery(sql);
                    if (rs.next()) {
                        int doceditionid = rs.getInt("doceditionid");
                        int docid = rs.getInt("id");
                        log.info("文档附件doceditionid:" + doceditionid + "，文档附件docid:" + docid);
                        if (doceditionid > 0) {
                            // 有多版本文件，取最新版本文档
                            sql = "select id from docdetail where doceditionid=" + doceditionid + " order by docedition desc";
                            rs.executeQuery(sql);
                            if (rs.next()) {
                                docid = rs.getInt("id");
                                log.info("有多版本文件，取最新版本文档docid:" + docid);
                            }
                        }

                        // 在新版本文档取最新附件
                        sql = "select f.imagefileid,f.imagefilename,f.filerealpath,d.imagefilename realname from docimagefile d,imagefile f where d.imagefileid=f.imagefileid and d.docid = " + docid + " orde by d.versionid desc";
                        rs.executeQuery(sql);
                        if (rs.next()) {
                            imagefileid = Util.null2String(rs.getString("imagefileid"));
                            filename = Util.null2String(rs.getString("realname"));
                            log.info("新版本文档取最新附件realname:" + filename + "，新版本文档取最新附件imagefileid:" + imagefileid);
                            if ("".equals(filename)) {
                                filename = Util.null2String(rs.getString("imagefilename"));
                            }
                            filerealpath = Util.null2String(rs.getString("filerealpath"));
                            log.info("新版本文档取最新附件filerealpath:" + filerealpath + "，新版本文档取最新附件imagefilename:" + filename);
                        }

                    }
                    /** 文档相关结束*/
                    fileRealPathList.add(filerealpath);

                    String extName = "";
                    if (filename.contains(".")) {
                        int bx = filename.lastIndexOf(".");
                        if (bx >= 0) {
                            extName = filename.substring(bx + 1);
                        }
                    }

                    int byteread;
                    byte[] data = new byte[1024];
                    InputStream imagefile = getImageFileInputStreamById(Util.getIntValue(imagefileid));
                    if (isOfficeToDocument(extName) && isMsgObjToDocument()) {
                        // 正文的处理
                        log.info("正文的处理！");
                        ByteArrayOutputStream bout = null;
                        try {

                            bout = new ByteArrayOutputStream();

                            while ((byteread = imagefile.read(data)) != -1) {
                                bout.write(data, 0, byteread);
                                bout.flush();
                            }
                            byte[] fileBody = bout.toByteArray();
                            iMsgServer2000 msgObj = new iMsgServer2000();
                            msgObj.MsgFileBody(fileBody); //将文件信息打包
                            fileBody = msgObj.ToDocument(msgObj.MsgFileBody());

                            imagefile = new ByteArrayInputStream(fileBody);

                            bout.close();

                        } catch (Exception e) {
                            log.error("文档正文输出文件流异常：" + e.getMessage());
                            throw new Exception("文档正文输出文件流异常：" + e.getMessage());
                        } finally {
                            if (bout != null) {
                                try {
                                    bout.close();
                                } catch (Exception ex) {
                                    log.error("关闭bout文件流异常：" + ex.getMessage());
                                }
                            }
                        }
                    }

                    FileOutputStream out = null;
                    try {
                        log.info("开始输出文档！");
                        String fileFolderCompare = fileTempFolder + filename;
                        // 防止附件重名
                        String newFileName = filename;
                        for (String fileRealPathTemp : fileRealPathTempList) {
                            if (fileFolderCompare.equals(fileRealPathTemp)) {
                                int lastIndex = filename.lastIndexOf(".");
                                if (lastIndex >= 0) {
                                    newFileName = filename.substring(0, lastIndex) + "_" + imagefileid + filename.substring(lastIndex);
                                } else {
                                    newFileName = filename + imagefileid;
                                }
                            }
                        }

                        fileTemp = fileCreate(fileTempFolder, newFileName);

                        out = new FileOutputStream(fileTemp);

                        while ((byteread = imagefile.read(data)) != -1) {
                            out.write(data, 0, byteread);
                            out.flush();
                        }
                        fileRealPathTempList.add(fileTempFolder + newFileName);

                    } catch (Exception ex) {
                        log.error("文档输出文件流异常：" + ex.getMessage());
                        throw new Exception("文档输出文件流异常：" + ex.getMessage());
                    } finally {
                        if (imagefile != null) {
                            try {
                                imagefile.close();
                            } catch (Exception ex) {
                                log.error("关闭imagefile文件流异常：" + ex.getMessage());
                            }
                        }
                        if (out != null) {
                            try {
                                out.flush();
                            } catch (Exception ex) {
                                log.error("刷新out文件流异常：" + ex.getMessage());
                            }
                        }
                        if (out != null) {
                            try {
                                out.close();
                            } catch (Exception ex) {
                                log.error("关闭out文件流异常：" + ex.getMessage());
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("解析文档文件信息异常：" + e.getMessage());
                }
            }
        }
    }

    /**
     * 查询附件信息
     *
     * @param fileIds
     * @param fileTempFolder
     * @param fileRealPathList
     * @param fileRealPathTempList
     * @throws Exception
     */
    public static void getAttachmentInfo(String fileIds, String fileTempFolder, List<String> fileRealPathList, List<String> fileRealPathTempList) {
        log.info("进入获取附件信息");
        RecordSet rsImageFileId = new RecordSet();

        File fileTemp = null;

        String sqlFileRealPath = "select t1.imagefilename,t1.filerealpath,t1.imagefileid,t2.imagefilename as realname " +
                " from imagefile t1 " +
                " left join docimagefile  t2 " +
                " on t1.imagefileid = t2.imagefileid " +
                " where t2.docid  in (" + fileIds + ")  ";
        log.info("getAttachmentInfo-sqlQuery：" + sqlFileRealPath);
        rsImageFileId.executeQuery(sqlFileRealPath);
        while (rsImageFileId.next()) {
            try {
                String imagefileid = Util.null2String(rsImageFileId.getString("imagefileid"));
                String filename = Util.null2String(rsImageFileId.getString("realname"));
                log.info("realname:" + filename + "，imagefileid:" + imagefileid);
                if ("".equals(filename)) {
                    filename = Util.null2String(rsImageFileId.getString("imagefilename"));
                }
                String filerealpath = Util.null2String(rsImageFileId.getString("filerealpath"));
                log.info("filerealpath:" + filerealpath + "，imagefilename:" + filename);
                fileRealPathList.add(filerealpath);

                String extName = "";
                if (filename.contains(".")) {
                    int bx = filename.lastIndexOf(".");
                    if (bx >= 0) {
                        extName = filename.substring(bx + 1);
                    }
                }

                int byteread;
                byte[] data = new byte[1024];
                InputStream imagefile = getImageFileInputStreamById(Util.getIntValue(imagefileid));
                if (isOfficeToDocument(extName) && isMsgObjToDocument()) {
                    // 正文的处理
                    log.info("正文的处理！");
                    ByteArrayOutputStream bout = null;
                    try {

                        bout = new ByteArrayOutputStream();

                        while ((byteread = imagefile.read(data)) != -1) {
                            bout.write(data, 0, byteread);
                            bout.flush();
                        }
                        byte[] fileBody = bout.toByteArray();
                        iMsgServer2000 msgObj = new iMsgServer2000();
                        msgObj.MsgFileBody(fileBody); //将文件信息打包
                        fileBody = msgObj.ToDocument(msgObj.MsgFileBody());

                        imagefile = new ByteArrayInputStream(fileBody);

                        bout.close();
                    } catch (Exception e) {
                        log.error("附件正文输出文件流异常：" + e.getMessage());
                        throw new Exception("附件正文输出文件流异常：" + e.getMessage());
                    } finally {
                        if (bout != null) {
                            try {
                                bout.close();
                            } catch (Exception ex) {
                                log.error("关闭bout文件流异常：" + ex.getMessage());
                            }
                        }
                    }
                }

                FileOutputStream out = null;
                try {
                    log.info("开始输出附件！");
                    String fileFoderCompare = fileTempFolder + filename;
                    // 防止附件重名
                    String newFileName = filename;
                    for (String fileRealPathTemp : fileRealPathTempList) {
                        if (fileFoderCompare.equals(fileRealPathTemp)) {
                            int lastIndex = filename.lastIndexOf(".");
                            if (lastIndex >= 0) {
                                newFileName = filename.substring(0, lastIndex) + "_" + imagefileid + filename.substring(lastIndex);
                            } else {
                                newFileName = filename + imagefileid;
                            }
                        }
                    }

                    fileTemp = fileCreate(fileTempFolder, newFileName);

                    out = new FileOutputStream(fileTemp);

                    while ((byteread = imagefile.read(data)) != -1) {
                        out.write(data, 0, byteread);
                        out.flush();
                    }
                    fileRealPathTempList.add(fileTempFolder + newFileName);
                } catch (Exception ex) {
                    log.error("附件输出文件流异常：" + ex.getMessage());
                    throw new Exception("附件输出文件流异常：" + ex.getMessage());
                } finally {
                    if (imagefile != null) {
                        try {
                            imagefile.close();
                        } catch (Exception ex) {
                            log.error("关闭imagefile文件流异常：" + ex.getMessage());
                        }
                    }
                    if (out != null) {
                        try {
                            out.flush();
                        } catch (Exception ex) {
                            log.error("刷新out文件流异常：" + ex.getMessage());
                        }
                    }
                    if (out != null) {
                        try {
                            out.close();
                        } catch (Exception ex) {
                            log.error("关闭out文件流异常：" + ex.getMessage());
                        }
                    }
                }
            } catch (Exception e) {
                log.error("解析附件文件信息异常：" + e.getMessage());
            }
        }
    }

    private static InputStream getImageFileInputStreamById(int imageFileIdOld) throws Exception {
        InputStream imagefile = null;
        try {
            log.info("开始生成文件流：" + imageFileIdOld);
            RecordSet rs = new RecordSet();
            String sql = "select t1.isaesencrypt,t1.aescode,t1.iszip,t1.imagefiletype,t1.imagefilename,t1.imagefileid,t1.filerealpath from imagefile t1 where t1.imagefileid = " + imageFileIdOld;
            log.info("getImageFileInputStreamById-sql：" + sql);
            rs.executeQuery(sql);
            if (rs.next()) {
                int imagefileid = Util.getIntValue(rs.getString("imagefileid"), 0);
                String filerealpath = Util.null2String(rs.getString("filerealpath"));
                String iszip = Util.null2String(rs.getString("iszip"));
                int isaesencrypt = Util.getIntValue(rs.getString("isaesencrypt"), 0);
                String aescode = Util.null2String(rs.getString("aescode"));

                if (StringUtils.isNotBlank(filerealpath)) {
                    File theFile = new File(filerealpath);
                    FileInputStream fileInputStream = new FileInputStream(theFile);
                    if ("1".equals(iszip)) {
                        ZipInputStream zin = new ZipInputStream(fileInputStream);;
                        if (zin.getNextEntry() != null) {
                            imagefile = new BufferedInputStream(zin);
                        }
                    } else {
                        imagefile = new BufferedInputStream(fileInputStream);
                    }
                } else {
                    ConnStatement statement = null;
                    try {
                        statement = new ConnStatement();
                        boolean isOracle = ("oracle".equals(statement.getDBType()));
                        log.info("isOracle：" + isOracle);
                        String sqlQuery = "select imagefile from ImageFile where  imagefileid=" + imagefileid;
                        log.info("getImageFileInputStreamById-sqlQuery：" + sqlQuery);
                        statement.setStatementSql(sqlQuery);
                        statement.executeQuery();
                        if (statement.next()) {
                            if (isOracle) {
                                imagefile = new BufferedInputStream(statement.getBlobBinary("imagefile"));
                            } else {
                                imagefile = new BufferedInputStream(statement.getBinaryStream("imagefile"));
                            }
                        }
                    } catch (Exception e) {
                        log.error("获取文件流异常：" + e.getMessage());
                    } finally {
                        if (statement != null) {
                            try {
                                statement.close();
                            } catch (Exception e) {
                                log.error("关闭文件流异常：" + e.getMessage());
                            }
                        }
                    }
                }
                if (isaesencrypt == 1) {
                    log.info("需要解密");
                    imagefile = AESCoder.decrypt(imagefile, aescode);
                }
            }
        } catch (Exception e) {
            log.error("解析文件数据异常：" + e.getMessage());
            throw new Exception("解析文件数据异常!");
        }
        return imagefile;
    }

    private static boolean isOfficeToDocument(String extName) {
        boolean isOfficeToDocument = false;
        if ("xls".equalsIgnoreCase(extName) || "doc".equalsIgnoreCase(extName) || "wps".equalsIgnoreCase(extName) || "ppt".equalsIgnoreCase(extName)
                || "docx".equalsIgnoreCase(extName) || "xlsx".equalsIgnoreCase(extName) || "pptx".equalsIgnoreCase(extName)) {
            isOfficeToDocument = true;
        }
        return isOfficeToDocument;
    }

    private static boolean isMsgObjToDocument() {
        boolean isMsgObjToDocument = true;
        String iWebOfficeClientName = Util.null2String(baseBean.getPropValue("weaver_obj", "iWebOfficeClientName"));
        boolean isIWebOffice2003 = iWebOfficeClientName.indexOf("iWebOffice2003") > -1 ? true : false;
        String isHandWriteForIWebOffice2009 = Util.null2String(baseBean.getPropValue("weaver_obj", "isHandWriteForIWebOffice2009"));
        if (isIWebOffice2003 || "0".equals(isHandWriteForIWebOffice2009)) {
            isMsgObjToDocument = false;
        }
        return isMsgObjToDocument;
    }

    public static File fileCreate(String fileFolder, String newFileName) throws Exception {
        try {
            log.info("开始生成文件！" + newFileName + "，文件夹：" + fileFolder);
            File folder = new File(fileFolder);
            File file = new File(fileFolder + newFileName);
            if (!folder.exists()) {
                folder.mkdirs();
            }
            if (file.exists()) {
                try {
                    file.delete();
                } catch (Exception e) {
                    log.error("删除文件异常：" + e.getMessage());
                }
            } else {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    log.error("创建文件异常：" + e.getMessage());
                }
            }
            log.info("生成文件路径：" + file.getPath());
            return file;
        } catch (Exception e) {
            log.error("操作文件异常：" + e.getMessage());
            throw new Exception("操作文件异常：" + e.getMessage());
        }

    }

    public static void deleteFile(String targetPath) throws IOException {
        File targgetFile = new File(targetPath);
        if (targgetFile.isDirectory()) {
            if (targetPath.contains("thirdBatchTemp")) {
                FileUtils.deleteDirectory(targgetFile);
            }

        } else if (targgetFile.isFile()) {
            targgetFile.delete();
        }

    }

    public static void downloadFile(HttpServletRequest request, HttpServletResponse response, String fileName, String path) throws Exception {
        InputStream ins = null;
        BufferedInputStream bins = null;
        OutputStream outs = null;
        BufferedOutputStream bouts = null;
        try {
            if (StringUtils.isNotBlank(path)) {
                File file = new File(path);
                if (file.exists()) {
                    log.info("开始下载文件！");
                    ins = new FileInputStream(path);
                    bins = new BufferedInputStream(ins);//放到缓冲流里面
                    outs = response.getOutputStream();//获取文件输出IO流
                    bouts = new BufferedOutputStream(outs);
                    String finalFileName = URLEncoder.encode(fileName, "UTF8");
                    final String agent = request.getHeader("USER-AGENT");
                    if ((agent.contains(" Chrome") || agent.contains("Safari")) && !agent.contains("Edge")) {
                        finalFileName = URLEncoder.encode(fileName.replaceAll("<", "").replaceAll(">", "").replaceAll("&lt;", "").replaceAll("&gt;", ""), "UTF-8").replaceAll("\\+", "%20").replaceAll("%28", "(").replaceAll("%29", ")").replaceAll("<", "").replaceAll(">", "").replaceAll("&lt;", "").replaceAll("&gt;", "").replaceAll("\\+", "%20").replaceAll("%28", "(")
                                .replaceAll("%29", ")").replaceAll("%7B", "{").replaceAll("%7D", "}").replaceAll("%5B", "[").replaceAll("%5D", "]").replaceAll("%40", "@").replaceAll("%23", "#").replaceAll("%25", "%").replaceAll("%26", "&")
                                .replaceAll("%2B", "+");
                    } else if (agent.contains("Firefox")) {
                        finalFileName = URLEncoder.encode(fileName.replaceAll("<", "").replaceAll(">", "").replaceAll("&lt;", "").replaceAll("&gt;", ""), "UTF-8").replaceAll("\\+", "%20").replaceAll("%28", "(").replaceAll("%29", ")");
                    } else {
                        finalFileName = URLEncoder.encode(fileName.replaceAll("<", "").replaceAll(">", "").replaceAll("&lt;", "").replaceAll("&gt;", ""), "UTF-8").replaceAll("\\+", "%20").replaceAll("%28", "(").replaceAll("%29", ")");
                    }


                    long filesize = 0;
                    int bytesRead = 0;
                    byte[] buffer = new byte[8192];
                    //开始向网络传输文件流
                    while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {
                        bouts.write(buffer, 0, bytesRead);
                        filesize += bytesRead;
                    }
                    log.info("filesize：" + filesize);
                    log.info("file.length：" + file.length());
                    response.setContentType("application/octet-stream");//设置response内容的类型
                    response.setHeader("Content-Disposition", "attachment; filename=\"" + finalFileName + "\"");
                    response.setHeader("Download-Filename", finalFileName);
                    response.setHeader("Content-Length", String.valueOf(file.length()));

                    bouts.flush();//这里一定要调用flush()方法
                    ins.close();
                    bins.close();
                    outs.close();
                    bouts.close();
                } else {
                    log.error("压缩文件不存在！");
                }
            }
        } catch (Exception e) {
            log.error("输出文件流异常：" + e.getMessage());
            throw new Exception(e.getMessage());
        } finally {
            if (ins != null) ins.close();
            if (bins != null) bins.close();
            if (outs != null) outs.close();
            if (bouts != null) bouts.close();
        }
    }

    public static String convertFileToBase64(File file) {
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            byte[] fileBytes = new byte[(int) file.length()];
            fileInputStream.read(fileBytes);
            return Base64.getEncoder().encodeToString(fileBytes);
        } catch (IOException e) {
            log.error("转换base64异常：" + e.getMessage());
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}
